package cn.sstir.api.common.exception;

/**
 * @title: ExceptionHandler
 * @description: 全局异常处理器
 * @author: fli
 * @email: fli@sstir.cn
 * @date: 2019/8/14 9:51
 */

import cn.sstir.fastspringboot.core.exception.ServiceException;
import cn.sstir.fastspringboot.core.reqres.response.ErrorResponse;
import cn.sstir.fastspringboot.core.reqres.response.Response;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.ConversionNotSupportedException;
import org.springframework.beans.TypeMismatchException;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.validation.BindException;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingPathVariableException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.context.request.async.AsyncRequestTimeoutException;
import org.springframework.web.multipart.support.MissingServletRequestPartException;
import org.springframework.web.servlet.NoHandlerFoundException;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

import javax.servlet.http.HttpServletRequest;

@RestControllerAdvice
@Order(-1)
@Slf4j
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {

    /**
     * 通用的接口映射异常处理方法
     * * HttpRequestMethodNotSupportedException.class,
     * * HttpMediaTypeNotSupportedException.class,
     * * HttpMediaTypeNotAcceptableException.class,
     * * MissingPathVariableException.class,
     * * MissingServletRequestParameterException.class,
     * * ServletRequestBindingException.class,
     * * ConversionNotSupportedException.class,
     * * TypeMismatchException.class,
     * * HttpMessageNotReadableException.class,
     * * HttpMessageNotWritableException.class,
     * * MethodArgumentNotValidException.class,
     * * MissingServletRequestPartException.class,
     * * BindException.class,
     * * NoHandlerFoundException.class,
     * * AsyncRequestTimeoutException.class
     */
    @Override
    protected ResponseEntity<Object> handleExceptionInternal(Exception ex, Object body, HttpHeaders headers, HttpStatus status, WebRequest request) {

        if (ex instanceof HttpRequestMethodNotSupportedException) {
            return ResponseEntity.ok(Response.error(ResponseEntityExceptionEnum.METHOD_NOT_ALLOWED));
        } else if (ex instanceof HttpMediaTypeNotSupportedException) {
            return ResponseEntity.ok(Response.error(ResponseEntityExceptionEnum.UNSUPPORTED_MEDIA_TYPE));
        } else if (ex instanceof HttpMediaTypeNotAcceptableException) {
            return ResponseEntity.ok(Response.error(ResponseEntityExceptionEnum.NOT_ACCEPTABLE));
        } else if (ex instanceof MissingPathVariableException) {
            return ResponseEntity.ok(Response.error(ResponseEntityExceptionEnum.MISSING_PATH_VARIABLE));
        } else if (ex instanceof MissingServletRequestParameterException) {
            return ResponseEntity.ok(Response.error(ResponseEntityExceptionEnum.MISSING_SERVLET_REQUEST_PARAMETER_ERROR));
        } else if (ex instanceof ServletRequestBindingException) {
            return ResponseEntity.ok(Response.error(ResponseEntityExceptionEnum.SERVLET_REQUEST_BINDING));
        } else if (ex instanceof ConversionNotSupportedException) {
            return ResponseEntity.ok(Response.error(ResponseEntityExceptionEnum.CONVERSION_NOT_SUPPORTED));
        } else if (ex instanceof TypeMismatchException) {
            return ResponseEntity.ok(Response.error(ResponseEntityExceptionEnum.TYPE_MIS_MATCH));
        } else if (ex instanceof HttpMessageNotReadableException) {
            return ResponseEntity.ok(Response.error(ResponseEntityExceptionEnum.HTTP_MESSAGE_NOT_READABLE));
        } else if (ex instanceof HttpMessageNotWritableException) {
            return ResponseEntity.ok(Response.error(ResponseEntityExceptionEnum.HTTP_MESSAGE_NOT_WRITABLE));
        } else if (ex instanceof MethodArgumentNotValidException) {
            return ResponseEntity.ok(Response.error(ResponseEntityExceptionEnum.METHOD_ARGUMENT_NOT_VALID));
        } else if (ex instanceof MissingServletRequestPartException) {
            return ResponseEntity.ok(Response.error(ResponseEntityExceptionEnum.MISSING_SERVLET_REQUEST_PART));
        } else if (ex instanceof BindException) {
            return ResponseEntity.ok(Response.error(ResponseEntityExceptionEnum.BINDING_EXCEPTION));
        } else if (ex instanceof NoHandlerFoundException) {
            return ResponseEntity.ok(Response.error(ResponseEntityExceptionEnum.NOT_FOUND));
        } else if (ex instanceof AsyncRequestTimeoutException) {
            return ResponseEntity.ok(Response.error(ResponseEntityExceptionEnum.SERVICE_UNAVAILABLE));
        } else {
            return ResponseEntity.ok(Response.error(ResponseEntityExceptionEnum.BAD_REQUEST));
        }
    }


    /**
     * 拦截业务异常
     */
    @ExceptionHandler(ServiceException.class)
    public Object serviceError(ServiceException e, HttpServletRequest request) {
        log.info("业务异常:", e);
        return new ErrorResponse(e.getCode(), e.getErrorMessage());
    }


}
